<script lang="ts" setup>
import { roleListGet, rolePermsPut, rolePost, rolePut, roleRoleIdDelete, roleRoleIdGet, } from '@/api';
import type { FormItems } from '@/components/CreateDrawer';
import CreateDrawer, { onShow } from '@/components/CreateDrawer';
import type { OMenuListGetItem, ORoleListGetItem, ORoleRoleIdGet } from '@/typed/response';
import { ORoleRoleIdGetValue } from '@/typed/response.value';
import { diffArray, getCheckedList } from '@/utils';
import CheckListItem from '@/views/console/system/components/CheckListItem.vue';
import { People28Regular } from '@vicons/fluent';
import { useDialog } from 'naive-ui';
import { onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';

const defaultValue = {
	roleId: null,
	roleName: null,
	roleKey: null,
	roleSort: null,
	status: 0,
	remark: null,
	id: null,
};

const formItems: FormItems = [
	{
		key: 'roleName',
		type: 'input',
		label: '角色名称',
		placeholder: '请输入角色名称',
		rule: [
			{
				required: true,
				message: '请输入角色名称',
				trigger: ['input', 'blur'],
			},
		],
	},
	{
		key: 'roleSort',
		type: 'input-number',
		label: '显示顺序',
		placeholder: '请输入角色顺序',
		rule: [
			{
				required: false,
				type: 'number',
				message: '请输入角色顺序',
				trigger: ['input', 'blur'],
			},
		],
	},
	{
		key: 'status',
		type: 'switch',
		label: '状态',
		checkedValue: 0,
		unCheckedValue: 1,
		rule: [
			{
				required: false,
				type: 'number',
				message: '请选择',
				trigger: ['input', 'blur'],
			},
		],
		slots: {
			checked: () => '正常',
			unchecked: () => '停用',
		},
	},
	{
		key: 'remark',
		type: 'textarea',
		label: '角色备注',
		placeholder: '请输入备注',
		rule: [
			{
				required: false,
				message: '请输入备注',
				trigger: ['input', 'blur'],
			},
		],
	},
];
const containerRef = ref();
const naiveDialog = useDialog();
const showSaveButton = ref(false);
const updateMenuLoading = ref(false);
const activeRoleId = ref(-1);
const roleList = ref<ORoleListGetItem[]>([]);
const detailLoading = ref(false);
const roleDetail = ref<ORoleRoleIdGet>({
	...ORoleRoleIdGetValue,
});
const newCheckedRoleList = ref<number[]>([]);
const menuList = ref<OMenuListGetItem[]>([]);

onMounted(async () => {
	await getRoleList();
});

function onCheckChange(value: any[]) {
	const result = getCheckedList(value);
	const newCheckedSorted = result.checked.sort();
	const oldCheckedSorted = roleDetail.value?.checkedIdList?.sort();
	const n = JSON.stringify(newCheckedSorted);
	const o = JSON.stringify(oldCheckedSorted);
	newCheckedRoleList.value = value;
	showSaveButton.value = n !== o && !roleDetail.value.admin;
}

async function setActiveRoleId(roleId: number) {
	showSaveButton.value = false;
	roleDetail.value = (roleList.value.find((i) => i.roleId === roleId) || {}) as ORoleRoleIdGet;
	activeRoleId.value = roleId
	await getRoleDetail();
}

async function onAddItem() {
	onShow();
}

async function onUpdateItem() {
	onShow(roleDetail.value);
}

function onDeleteItem() {
	naiveDialog.error({
		title: '提示',
		content: '删除该数据？',
		positiveText: '确认',
        negativeText: '取消',
		onPositiveClick: async () => {
			try {
				const res = await roleRoleIdDelete(activeRoleId.value);
				if (res.data) {
					window.$message.success('操作成功');
					//containerRef.value.reload();
                    await getRoleList();
				}
			} catch (error) {
			    console.log(error)
				window.$message.error('操作失败');
			}
		},
	});
}

async function onHandleRoleCreateDrawerSubmit() {
	await getRoleList();
}

function filterNoChildren(list: any[]): any[] {
	return list
	.map((i) => {
		if (i.children) {
			let child = filterNoChildren(i.children).filter((i) => i.checked);
			return {
				menuId: i.menuId,
				checked: child.length > 0,
				name: i.menuName,
				children: child,
			};
		} else {
			return {
				menuId: i.menuId,
				checked: i.checked,
				name: i.menuName,
			};
		}
	})
	.filter((i) => i.checked);
}

async function onUpdateMenuIdList() {
	updateMenuLoading.value = true;
	// 更新前，重新请求服务器端最新数据，防止被覆盖
	const {data: roleDetailSub} = await roleRoleIdGet(activeRoleId.value);
	// 旧数据
	const oldDetailIds = roleDetail.value?.checkedIdList
	// 新数据
	const newDetailIds = roleDetail.value?.checkedIdList
	// 对比前后的差
	const diffArr = diffArray(oldDetailIds, newDetailIds);
	let menuIds: number[] = getCheckedList(filterNoChildren(newCheckedRoleList.value)).checked;

	// 对比当前选择的和原数据的差异
	const diffOldArr = diffArray(oldDetailIds, menuIds);
	// 从当前结果中剔除已被删除的
	diffArr.del.forEach((i) => {
		if (!diffOldArr.add.includes(i)) {
			const index = menuIds.indexOf(i);
			if (index > -1) {
				menuIds.splice(index, 1);
			}
		}
	});
	// 从当前结果中添加已其他人已添加的
	diffArr.add.forEach((i) => {
		if (!diffOldArr.del.includes(i)) {
			menuIds.push(i);
		}
	});
	menuIds = menuIds.sort((a, b) => {
		return a - b;
	});

	const {data} = await rolePermsPut({
		roleId: activeRoleId.value,
		menuIds,
	});
	updateMenuLoading.value = false;
	if (data) {
		window.$message.success('操作成功');
		await getRoleDetail();
		showSaveButton.value = false;
	}
}

async function getRoleDetail() {
	detailLoading.value = true;
	const {data} = await roleRoleIdGet(activeRoleId.value);
	detailLoading.value = false;
	if (data) {
		roleDetail.value = data;
		menuList.value = data.menuList
	}
}

async function getRoleList() {
	const {data} = await roleListGet();
	if (data) {
		roleList.value = data;
		if (data.length > 0) {
			await setActiveRoleId(activeRoleId.value === -1 ? data[0].roleId : activeRoleId.value);
		}
	}
}

</script>
<template>
	<div class="outPage">
		<div class="rolePage">
			<div class="leftList">
				<header>
					<div class="title">角色</div>
					<n-button
						type="primary"
						text
						@click="onAddItem"
					>
						添加
					</n-button>
				</header>
				<div class="list">
					<template v-for="item in roleList" :key="item.roleId">
						<div class="iconWrap" @click="setActiveRoleId(item.roleId)">
							<n-icon>
								<People28Regular/>
							</n-icon>
							<div :class="`item ${item.roleId === activeRoleId ? 'active' : ''}`">
								<div class="name" v-if="item.status === 0">
									<n-ellipsis tooltip>
										{{ item.roleName }}
									</n-ellipsis>
								</div>
								<div class="name disabled" v-else>
									<s>
										<n-ellipsis tooltip>
											{{ item.roleName }}
										</n-ellipsis>
									</s>
								</div>
								<div class="desc">
									<n-ellipsis tooltip>
										{{ item.remark || '--' }}
									</n-ellipsis>
								</div>
							</div>
						</div>
						<n-divider/>
					</template>
				</div>
			</div>
			<div class="rightList">
				<header>
					<div class="title">
						<span>{{ roleDetail.roleName }}</span>
					</div>
					<div v-if="!roleDetail.admin">
						<n-button
							type="error"
							size="small"
							@click="onDeleteItem"
						>
							删除
						</n-button>
						<n-button
							type="primary"
							size="small"
							@click="onUpdateItem"
						>
							编辑
						</n-button>
					</div>
				</header>
				<section>
					<n-spin class="list" :show="detailLoading">
						<div class="iconWrap">
							<div class="item">
								<div class="label">一级菜单</div>
								<div class="checkList">二级菜单</div>
							</div>
						</div>
						<n-divider/>
						<div class="scrollList">
							<CheckListItem
								:data="menuList"
								:admin="roleDetail.admin"
								:checkedList="roleDetail.checkedIdList"
								@change="onCheckChange"
							/>
						</div>
						<div class="saveButton" v-if="showSaveButton">
							<n-button
								type="primary"
								style="width: 120px"
								:loading="updateMenuLoading"
								@click="onUpdateMenuIdList"
							>
								保存修改
							</n-button>
						</div>
					</n-spin>
				</section>
			</div>
		</div>
		<CreateDrawer
			rowKey="roleId"
			labelWidth="120"
			:defaultValue="defaultValue"
			:formItems="formItems"
			:postRequestPromise="rolePost"
			:putRequestPromise="rolePut"
			@submit="onHandleRoleCreateDrawerSubmit"
		/>
	</div>
</template>

<style scoped lang="less">
.rolePage,
.outPage {
	width: 100%;
	display: flex;
	align-items: stretch;
	justify-content: stretch;
	border-radius: 4px;
}

.outPage {
	height: calc(100% - 60px);
}

header {
	height: 73px;
	padding: 20px;
	display: flex;
	align-items: center;
	flex-shrink: 0;
	border-bottom: 1px solid var(--border-color);
	justify-content: space-between;

	.title {
		font-size: 16px;
		font-weight: bold;
	}

	:deep(.n-button) {
		margin-left: 10px;
	}
}

.list {
	flex-grow: 1;
	height: 0;

	:deep(.n-spin-content) {
		flex-grow: 1;
		height: 0;
		display: flex;
		flex-direction: column;
	}

	:deep(.n-divider) {
		margin: 0;
	}

	.iconWrap {
		padding: 10px 20px;
		display: flex;
		align-items: flex-start;
		cursor: pointer;

		.iconWrap {
			padding: 0;
			margin-bottom: 10px;
		}

		:deep(.n-icon) {
			margin-right: 10px;
			padding-top: 3px;
		}

		&.active,
		&:hover {
			background-color: var(--border-color);
		}
	}

	.item {
		flex-grow: 1;
		transition-duration: 0.2s;

		.name {
			font-size: 14px;

			&.disabled {
				color: var(--error-color);
			}
		}

		.desc {
			font-size: 12px;
			opacity: 0.5;
		}
	}
}

.leftList {
	width: 160px;
	flex-shrink: 0;
	display: flex;
	flex-direction: column;
	border-right: 1px solid var(--border-color);

	.list {
		overflow: auto;

		.item {
			&.active,
			&:hover {
				color: var(--primary-color);
			}
		}
	}
}

.rightList {
	flex-grow: 1;
	display: flex;
	flex-direction: column;

	.iconWrap {
		cursor: unset;
	}

	section {
		display: flex;
		flex-direction: column;
		flex-grow: 1;
		height: 0;
	}

	.list {
		display: flex;
		flex-direction: column;
		flex-grow: 1;
		height: 0;

		> .iconWrap:first-child {
			color: inherit;
			opacity: 0.6;

			&:hover {
				background-color: transparent;
				color: inherit;
			}
		}

		.item {
			display: flex;

			.label {
				width: 160px;
				flex-shrink: 0;
			}

			.checkList {
				flex-grow: 1;
				display: flex;
				flex-wrap: wrap;
			}

			.checkAll {
				width: 80px;
				flex-shrink: 0;
				display: flex;
				align-items: center;
				justify-content: center;
			}
		}

		.scrollList {
			overflow: auto;
			flex-grow: 1;
			height: 0;
		}

		.saveButton {
			height: 60px;
			display: flex;
			align-items: center;
			justify-content: center;
			border-top: 1px solid var(--border-color);

			:deep(.n-button):not(:last-child) {
				margin-right: 20px;
			}
		}
	}
}
</style>
